const child_process_1 = require("child_process");
const netstring = require('netstring');

class Streamer{
    constructor() {
        this.workerBinPath = '/home/wchi/Desktop/transport-worker';
        this.workerArgs = [];

        //用于跟踪流的相关信息
        this.streamList = [];

        console.info(`start to load child process, path:${this.workerBinPath}`);
        this._child = child_process_1.spawn(
            // command
            this.workerBinPath,
            // args
            this.workerArgs,
            // options
            {
                env: {
                    MEDIASOUP_VERSION: '3.7.15',
                    ...process.env
                },
                detached: false,
                // fd 0 (stdin)   : Just ignore it.
                // fd 1 (stdout)  : Pipe it for 3rd libraries that log their own stuff.
                // fd 2 (stderr)  : Same as stdout.
                // fd 3 (channel) : Producer Channel fd.
                // fd 4 (channel) : Consumer Channel fd.
                // fd 5 (channel) : Producer PayloadChannel fd.
                // fd 6 (channel) : Consumer PayloadChannel fd.
                stdio: ['ignore', 'pipe', 'pipe', 'pipe', 'pipe', 'pipe', 'pipe'],
                windowsHide: true
            });

        this.producerSocket = this._child.stdio[3];
        this.consumerSocket = this._child.stdio[4];
        this.producerPayloadSocket = this._child.stdio[5];

        this.consumerSocket.on('data', buffer =>{
            if (buffer.byteLength < 300) {
                console.info('receive data:' + buffer.toString());
            }else{
                console.info('receive data, length:' + buffer.byteLength);
            }
        });

        this._child.on('exit', (code, signal) => {
            this._child = undefined;
            this.close();
            console.info('fail to start process,exit', code, signal);
        });

        this._child.on('error', (error) => {
            this._child = undefined;
            this.close();
            console.info('fail to start process,error', error);
        });

        // Be ready for 3rd party worker libraries logging to stdout.
        this._child.stdout.on('data', (buffer) => {
            for (const line of buffer.toString('utf8').split('\n')) {
                if (line)
                    console.info(`(stdout) ${line}`);
            }
        });

        // In case of a worker bug, mediasoup will log to stderr.
        this._child.stderr.on('data', (buffer) => {
            for (const line of buffer.toString('utf8').split('\n')) {
                if (line)
                    console.info(`(stderr) ${line}`);
            }
        });
    }

    /**
     * 增加新的流配置
     * @param id    流对应的id，字符串类型
     * @param audioParam    音频参数
     * @param videoParam    视频参数
     * @param forwardUrl    转发地址
     */
    startStream({streamId, audioParam={}, videoParam={}, forwardUrl}){
        if (this.streamList.includes(streamId)) {
            throw new Error('streamId already exists');
        }
        this.streamList.push(streamId);
        console.log(`start stream, param:${JSON.stringify(arguments[0])}`)

        let configMsg = {
            id:streamId,
            type:'config',
            audio:audioParam,
            video:videoParam,
            forward:{
                url:forwardUrl
            }
        }
        this._writeMsg(configMsg, this.producerSocket);
    }

    /**
     * 停止流的处理
     * @param streamId 流id
     */
    stopStream(streamId){
        console.info(`start to stop stream:${streamId}`);

        let index = this.streamList.indexOf(streamId);
        if (index<0) {
            console.warn(`stopStream failed, not exist streamId:${streamId}`);
            throw new Error('streamId not exists:' + streamId);
        }
        this.streamList.splice(index,1);
    }

    _writeMsg(obj, socket){
        const ns = netstring.nsWrite(JSON.stringify(obj));
        // This may throw if closed or remote side ended.
        socket.write(ns);
    }

    /**
     * 发送音频数据
     * @param streamId    流媒体id
     * @param pcmData  音频PCM数据
     */
    sendAudio(streamId, pcmData){
        if (!this.streamList.includes(streamId)) {
            throw new Error('stream not exist');
        }

        let header = {id: streamId, type:"audio"};
        this._writeMsg(header, this.producerPayloadSocket);

        const ns = netstring.nsWrite(pcmData);
        this.producerPayloadSocket.write(ns);
    }

    /**
     * 发送视频数据
     * @param streamId    流媒体id
     * @param rgbData  视频RGB数据
     */
    sendVideo(streamId, rgbData){
        if (!this.streamList.includes(streamId)) {
            throw new Error('stream not exist');
        }

        let header = {id: streamId, type:"video"};
        this._writeMsg(header, this.producerPayloadSocket);

        const ns = netstring.nsWrite(rgbData);
        this.producerPayloadSocket.write(ns);
    }

    /**
     * 关闭当前的streamer
     */
    close(){
        if (this._child.connected) {
            console.info('start to close streamer');
            try {
                this._child.kill();
            }catch (e) {
                console.warn('fail to close streamer', e);
            }
        }
    }
}
module.exports = Streamer

